-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Warn if implicit default shadows given #23559
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
I didn't think to bootstrap; there are many instances, including the classic
|
Could offer a quickfix that inlines the default. |
4bb349c
to
9e53b78
Compare
I think this warning would be too noisy. Implicit defaults are there for a reason, we do not want to warn each time we use one. Also the change set looks too big and risky for such a relatively minor improvment. |
It would be interesting to see how frequently this warning pops up in the open community build to have an understanding of how frequently these situations occur. |
The recursion case is the Scala 2 lint. I find it very confusing for the reason cited on the ticket: was this intentional or an error? The compiler can't help you decide, but you feel better about it if someone had to type in For the In fact, it might be cleaner to refuse to supply defaults in those cases. However, I haven't spent time thinking abstractly about it. Noisy warnings are usually behind a flag; I wasn't sure if the compiler team wants to go that route, since flags (even for warnings) are also a maintenance burden and a challenge for cross-builds (especially under |
Not sure about indirect recursion (where Scala 2 warns for the same reason)
For fun, I'll try doing the check at |
Similar to the Scala 2 lint for "named boolean parameters" where you must name them if necessary to avoid ambiguity or accidentally switching args, one boolean parameter with a default might by OK (where there is one use site which requires the alternate behavior or state) but more than one is hard to follow, especially when recursing. But that sounds like a third-party lint. (The named boolean lint was added as a project-internal lint on Scala 2.) Implicit primitives add extra eye blinking. |
9e53b78
to
f038825
Compare
Put the recursion under a flag, but leave the titular warning. I didn't retry the scaladoc test, which probably requires the "special syntax" for a satisfying fix. |
As suspected, the scaladoc case is noticed, appropriately.
I will nowarn it for now, rather than munging the code. |
f038825
to
c7045ea
Compare
I overlooked that. Yes, this is indeed confusing and should be avoided. |
c7045ea
to
b144877
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's on the right track, but i would try to do without the UsedDefault
attachment.
override protected def explain(using Context): String = | ||
"Usually it's intended to prefer the given in scope, but you must specify it explicitly." | ||
|
||
final class TailrecUsedDefault(using Context) extends TypeMsg(TailrecUsedDefaultID): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's not restricted to tailrec calls, the class should be renamed, maybe to RecursiveUsesDefault
?
if isRecursiveCall then | ||
if ctx.settings.Whas.recurseWithDefault && tree.args.exists(_.hasAttachment(UsedDefaults)) then | ||
report.warning(TailrecUsedDefault(), tree.srcPos) | ||
|
||
if (inTailPosition) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be a tailrec call only if inTailPosition
is true.
@@ -42,6 +42,9 @@ import dotty.tools.dotc.inlines.Inlines | |||
object Applications { | |||
import tpd.* | |||
|
|||
/** Attachment indicating that an argument in an application was a default arg. */ | |||
val UsedDefaults = Property.StickyKey[Unit] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That will not work in from tasty compilation, since attachments are not pickled.
@@ -325,7 +326,10 @@ class TailRec extends MiniPhase { | |||
method.matches(calledMethod) && | |||
enclosingClass.appliedRef.widen <:< prefix.tpe.widenDealias | |||
|
|||
if (isRecursiveCall) | |||
if isRecursiveCall then | |||
if ctx.settings.Whas.recurseWithDefault && tree.args.exists(_.hasAttachment(UsedDefaults)) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider finding a more local way to figure this out, one that does not span most of the compiler with a time-travelling attachment. Maybe look at spans? Or else check whether the argument's symbol is a default getter.
@@ -774,6 +777,14 @@ trait Applications extends Compatibility { | |||
methodType.isImplicitMethod && (applyKind == ApplyKind.Using || failEmptyArgs) | |||
|
|||
if !defaultArg.isEmpty then | |||
if methodType.isImplicitMethod && ctx.mode.is(Mode.ImplicitsEnabled) | |||
&& inferImplicitArg(formal, appPos.span).tpe.isError == false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
&& inferImplicitArg(formal, appPos.span).tpe.isError == false | |
&& !inferImplicitArg(formal, appPos.span).tpe.isError |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was intentional, since the operator is so far away from the word it negates. I could introduce a var for such a case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It also reads as "did not infer an implicit arg"...
-Wrecurse-with-default warns on self-recursion with default arg.
Reminder that this is especially brittle, even if it warns about unused nowarn. By the time my PR is merged, I don't know if the error IDs will have migrated. It needs a special comment to
|
Only 13 warnings for compiler under The warnings for scaladoc:
I will fix the E219s at least, where I think "use current implicit" was intended. |
b144877
to
27588b0
Compare
Much improved by following the review advice. Rebased and squashed. The scaladoc fix is a separate commit in case my guesses were wrong. I see it doesn't report the parameter name: |
Fixes #23541
When supplying a default arg for an implicit application, warn if there is an implicit value available.
That is for
f(using x = v)
where a default is supplied inf(using x = v, y = default)
. The user might think the implicit value is supplied, which is not the case for explicitusing
; this is especially confusing in a recursive call, where the user intends to "replace" an implicit parameter.Separately, behind a flag, warn if any recursive call uses a default arg instead of passing the current parameter value.
-Wrecurse-with-default
,"Warn when a method calls itself with a default argument."